import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom/server';
import serialize from 'serialize-javascript';
import Helmet from 'react-helmet';

// Utils和Helpers都可以表示工具集和辅助模块，但是Helpers中的模块通常需要实例化，而Utils则放置一些函数。
// 因此，不仅是Html组件，这里将配置store的函数以及常用的工具函数都放在src/utils下面。
// 不过，目录的命名要求并不严格，可以根据自己和团队习惯灵活安排目录结构。

function Html(props) {

  // 接收Webpack同构工具提供的键值对对象、React组件component以及Redux的store作为props。
  const { assets, component, store } = props;

  const content = component ? ReactDOM.renderToString(component) : '';
  const head = Helmet.rewind();

  return (
    <html lang="zh-CN">
      <head>
        {/*使用react-helmet管理文档头信息，包括title、meta、link、script和base tags。*/}
        {head.base.toComponent()}
        {head.title.toComponent()}
        {head.meta.toComponent()}
        {head.link.toComponent()}
        {head.script.toComponent()}

        <link rel="shortcut icon" href="/favicon.ico" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />

        {/*通过遍历Webpack同构工具提供的资源键值对对象，给HTML添加独立出来的样式文件。注意，只有在生产环境下，assets.styles才包含数据。*/}
        {Object.keys(assets.styles).map((style, key) =>
          <link
            href={assets.styles[style]} key={key} media="screen, projection"
            rel="stylesheet" type="text/css"
            charSet="UTF-8"
          />
        )}
      </head>
      <body>
      {/*使用dangerouslySetInnerHTML渲染HTML字符串到组件中。默认情况下，React会对HTML进行编码来防止XSS攻击。
      如果你实在想渲染HTML字符串，应该使用dangerouslySetInnerHTML。
      React故意使用这个笨重、醒目的语法来让开发者不会意外渲染文本作为HTML，继而导致XSS漏洞。*/}
        <div id="app" dangerouslySetInnerHTML={{ __html: content }} />
      {/*渲染来自服务端的预载state*/}
        <script
          dangerouslySetInnerHTML={{
            // serialize用于将JSON转换为字符串，它和JSON.stringify()的区别在于可以输出JSON中的函数和正则表达式。另外，它也包含自动编码功能来防止XSS攻击
            __html: `window.__INITIAL_STATE__=${serialize(store.getState())};`
          }}
          charSet="UTF-8"
        />
        {/*用于客户端渲染的脚本文件。*/}
        <script src={assets.javascript.main} charSet="UTF-8" />
      </body>
    </html>
    );
}

Html.propTypes = {
  assets: PropTypes.object,
  component: PropTypes.node,
  store: PropTypes.object
};

export default Html;
